home *** CD-ROM | disk | FTP | other *** search
/ NetNews Offline 2 / NetNews Offline Volume 2.iso / news / comp / lang / c++-part2 / 16503 < prev    next >
Encoding:
Text File  |  1996-08-05  |  5.6 KB  |  152 lines

  1. Path: news.crd.ge.com!rebecca!rpi!not-for-mail
  2. From: rcauvin@natinst.com (Roger L. Cauvin)
  3. Newsgroups: comp.lang.c++,comp.lang.c++.moderated
  4. Subject: Comparison Operators Solution (was Re: Virtual function question)
  5. Date: 10 Apr 1996 18:28:21 -0000
  6. Organization: National Instruments
  7. Sender: cppmods@netlab.cs.rpi.edu
  8. Approved: Dietmar.Kuehl@uni-konstanz.de
  9. Message-ID: <4kguk5$5au@netlab.cs.rpi.edu>
  10. References: <4jp6e9$ou5@dub-news-svc-1.compuserve.com> <4ked7o$8g3@dub-news-svc-1.compuserve.com>
  11. NNTP-Posting-Host: netlab.cs.rpi.edu
  12. X-Original-Date: 10 Apr 1996 17:45:52 GMT
  13.  
  14. In article <4ked7o$8g3@dub-news-svc-1.compuserve.com>, RossBoylan@aol.com
  15. (Ross Boylan) wrote:
  16.  
  17. > Problem:  To define the comparison operators <, <=, >, ==, etc in
  18. > terms of one or two primitives (< and maybe ==), so that all classes
  19. > for which the comparisons make sense only require definition of the
  20. > primitives.
  21. > Solutions
  22. > 1) The best solution I've seen is in the Standard Template library
  23. > My original problem statement used member functions, but the symmetric
  24. > free-standing functions are more appropriate to the comparison
  25. > operators. 
  26. > 2)  The remaining solutions use member functions (Borland's library
  27. > apparently does this) and create bogus functions which take abstract
  28. > classes as arguments.  In the following, RBMagnitude::operator< is not
  29. > virtual, so subclasses do not need to override it (they ignore it
  30. > instead).
  31. > 3) Several people suggested casting down as a possibility
  32. > 4) My original problem defined all RBMagnitude operators as virtual.
  33. > I have some potential subclasses which redefine all the inequality
  34. > operators.  However, the gain in computing comparisons directly may be
  35. > offset by the overhead of virtual functions, and it is probably
  36. > clearner not to use virtual functions.
  37. > 5) Scott Meyer's new book, More Effective C++, has some material in
  38. > item 33 which may be relevant (I haven't had a chance to look at it
  39. > yet).
  40.  
  41. I consider none of the "solutions" offered above to be ideal.  A solution
  42. that I do consider to be ideal is similar to the second proposal. 
  43. Conceptually, any class of objects that allows comparison operations
  44. is-a-kind-of comparable object.  So how about a ComparableObject abstract
  45. base class?  It should actually be a class template:  a number is
  46. comparable to other numbers and to native numeric types, a string is
  47. comparable to other strings and to native C strings.  The template
  48. parameter specifies the type of the value with which a ComparableObject
  49. can be compared.  Concrete classes such as Number and String are derived
  50. from ComparableObject template class(es).
  51.  
  52. The following solution maximizes code sharing and concepual clarity, and
  53. allows overriding of all the comparison operations:
  54.  
  55. template <class ValueType>
  56. class ComparableObject
  57.   {
  58.   public:
  59.     friend bool operator==(const ComparableObject &comparableObject,
  60. ValueType value);
  61.     friend bool operator==(ValueType value, const ComparableObject
  62. &comparableObject);
  63.     friend bool operator!=(const ComparableObject &comparableObject,
  64. ValueType value);
  65.     friend bool operator!=(ValueType value, const ComparableObject
  66. &comparableObject);
  67.     friend bool operator<(const ComparableObject &comparableObject,
  68. ValueType value);
  69.     friend bool operator<(ValueType value, const ComparableObject
  70. &comparableObject);
  71.     friend bool operator<=(const ComparableObject &comparableObject,
  72. ValueType value);
  73.     friend bool operator<=(ValueType value, const ComparableObject
  74. &comparableObject);
  75.     friend bool operator>(const ComparableObject &comparableObject,
  76. ValueType value);
  77.     friend bool operator>(ValueType value, const ComparableObject
  78. &comparableObject);
  79.     friend bool operator>=(const ComparableObject &comparableObject,
  80. ValueType value);
  81.     friend bool operator>=(ValueType value, const ComparableObject
  82. &comparableObject);
  83.  
  84.   protected:
  85.     virtual bool IsEqualTo(ValueType value) = 0;
  86.     virtual bool IsNotEqualTo(ValueType value);
  87.     virtual bool IsLessThan(ValueType value) = 0;
  88.     virtual bool IsLessThanOrEqualTo(ValueType value);
  89.     virtual bool IsGreaterThan(ValueType value);
  90.     virtual bool IsGreaterThanOrEqualTo(ValueType value);
  91.  
  92.   private:
  93.   };
  94.  
  95. Comparison operators in ComparableObject are implemented as calls to
  96. protected virtual functions.  E.g.:
  97.  
  98. bool operator!=(const ComparableObject &comparableObject, ValueType value)
  99.   {
  100.   return comparableObject.IsNotEqualTo(value);
  101.   }
  102.  
  103. The protected virtual functions are implemented in terms of the equal to
  104. and less than operations:
  105.  
  106. bool ComparableObject::IsNotEqualTo(ValueType value)
  107.   {
  108.   return !IsEqualTo(value);
  109.   }
  110.  
  111. Derived classes need only provide implementations for IsEqualTo and IsLessThan:
  112.  
  113. class Number : public virtual ComparableObject<const Number &>,
  114.                public virtual ComparableObject<double>
  115.   {
  116.   public:
  117.  
  118.   protected:
  119.     virtual bool IsEqualTo(const Number &value);
  120.     virtual bool IsLessThan(const Number &value);
  121.     virtual bool IsEqualTo(double value);
  122.     virtual bool IsLessThan(double value);
  123.  
  124.   private:
  125.   };
  126.  
  127. The Number class now supports all comparison operations by defining them
  128. in terms of two primitive operations per value type.  This solution is
  129. superior to STL's function templates for at least two reasons.  First, all
  130. operations are overridable by derived classes.  Second, there are fewer
  131. template instantiations than in STL's technique.
  132.  
  133.  
  134. Roger
  135.  
  136. ---
  137.  
  138. Roger L. Cauvin
  139. rcauvin@natinst.com
  140. Software Engineer
  141. National Instruments
  142.  
  143.       [ Articles to moderate: mailto:c++-submit@netlab.cs.rpi.edu ]
  144.       [  Read the C++ FAQ: http://www.connobj.com/cpp/cppfaq.htm  ]
  145.       [  Moderation policy: http://www.connobj.com/cpp/guide.htm  ]
  146.       [      Comments? mailto:c++-request@netlab.cs.rpi.edu       ]
  147.